﻿using DeHeng_Mes.Dao;
using DeHeng_Mes.Dao.PlcDao;
using DeHeng_Mes.Model;
using DeHeng_Mes.Model.Boss;
using DeHeng_Mes.Model.ConfigModel;
using DeHeng_Mes.Model.OrderSingleton;
using DeHeng_Mes.Model.Singleton;
using DeHeng_Mes.Model.Table;
using DeHeng_Mes.PlcService;
using DeHeng_Mes.Utils;
using FluentFTP;
using Newtonsoft.Json;
using NPOI.SS.Formula.Functions;
using S7.Net;
using S7.Net.Types;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Shapes;
using DateTime = System.DateTime;
using Path = System.IO.Path;

namespace DeHeng_Mes.Service
{
    public class PlcServicees
    {
        #region 成员实例
        PlcDao plcDao = new PlcDao();
        OrderDao orderDao = new OrderDao();
        ProductionPowerDao productionPowerDao = new ProductionPowerDao();
        List<PlcOrderConfigModel> readPlcList = PlcOrderConfigModelList.ReadPlcList;
        ExitService exitService= new ExitService();
        #endregion

        /// <summary>
        /// 获取当日能耗和产量
        /// </summary>
        /// <param name="isTimer"></param>
        public void GetPowerAndProdution(bool isTimer)
        {
            // 检查连接状态并查询工单
            foreach (var item in PlcConnectionManager.plcContainer)
            {
                // 未连接跳出本层
                if (!item.isConnected)
                    continue;

                // 获取Plc数据
                Dictionary<object, Type> dictionary = MappingTable.PlcMapping(item.plc, item.name);

                // 获取当前日期
                DateTime currentDate = DateTime.Now;

                // 获取天
                DateTime previousDate = isTimer ? currentDate.AddDays(-1) : currentDate;

                string day = previousDate.Day.ToString();

                // 获取当前年月日
                string date = $"{previousDate.Year}{previousDate.Month:D2}{previousDate.Day:D2}";

                // 判断当前plcName，执行不同方法
                switch (item.name)
                {
                    case "DOOR-01":
                        break;
                    case "DOOR-02":
                        // 执行当日产量采集
                        Dictionary<string, object> productionDic = plcDao.GetFieldValues(dictionary, "Production");

                        // 初始化产量
                        string production = string.Empty;

                        // 获取产量
                        foreach (var productions in productionDic)
                        {
                            if (productions.Key.Replace("Day", "").Equals(day))
                            {
                                production = productions.Value.ToString();
                            }
                        }

                        // 存入当天产量数据
                        if (!string.IsNullOrEmpty(production))
                        {
                            // 判断产量数据是否保存
                            if (productionPowerDao.ProductionIsSave(item.name, date, production))
                                // 执行更新操作
                                productionPowerDao.UpdateProduction(item.name, date, production);
                            else
                                //执行插入操作
                                productionPowerDao.ProductionSave(item.name, date, production);
                        }
                        break;
                }

                // 执行当日能耗采集
                Dictionary<string, object> powerDic = plcDao.GetFieldValues(dictionary, "Power");

                // 初始化当天能耗
                string power = string.Empty;

                // 获取当天能耗
                foreach (var powers in powerDic)
                {
                    if (powers.Key.Replace("Day", "").Equals(day))
                    {
                        power = powers.Value.ToString();
                    }
                }

                // 存入当天能耗数据
                if (!string.IsNullOrEmpty(power))
                {
                    // 判断能耗数据是否保存
                    if (productionPowerDao.PowerIsSave(item.name, date, power))
                        // 执行更新操作
                        productionPowerDao.UpdatePower(item.name, date, power);
                    else
                        //执行插入操作
                        productionPowerDao.PowerSave(item.name, date, power);
                }
            }
        }

        /// <summary>
        /// 0点监控
        /// </summary>
        public async Task Timer()
        {
            while (true)
            {
                // 获取当前时间
                DateTime now = DateTime.Now;

                // 判断是否为凌晨0点
                // 判断是否为凌晨0点
                if (now.Hour == 0 && now.Minute == 0 && now.Second == 0)
                {
                    GetPowerAndProdution(true);
                }
                await Task.Delay(900);
            }
        }

        /// <summary>
        /// 存储拉铆数据
        /// </summary>
        /// <returns></returns>
        public async Task ReadRiveteData()
        {
            while (true)
            {
                try
                {
                    for (int i = 1; i <= 4; i++)
                    {
                        await ReveteConnection(i);
                    }
                    // 延迟5秒读取
                    await Task.Delay(5000);
                }
                catch (Exception ex)
                {
                    Tools.ProduceLogText($"读取并保存拉铆数据发生异常：原因是：{ex.Message}");
                }
            }
        }

        private async Task ReveteConnection(int count)
        {
            // 初始化文件夹路径
            string directory = $@"D:\LM\before\{count}\Data_Info\{DateTime.Now.ToString("yyyy")}{DateTime.Now.ToString("MM")}\{DateTime.Now.ToString("yyyy")}{DateTime.Now.ToString("MM")}{DateTime.Now.ToString("dd")}";

            if (Directory.Exists(directory))
            {
                // 获取目录下所有CSV文件路径
                string[] csvFiles = Directory.GetFiles(directory, "*.csv");

                foreach (string filePath in csvFiles)
                {

                    if (filePath.Contains("_Save"))
                        continue;

                    // 提取文件名和扩展名
                    string fileName = Path.GetFileNameWithoutExtension(filePath);
                    string extension = Path.GetExtension(filePath); // 如 ".csv"

                    // 构建新文件名：原文件名 + "_Save" + 扩展名
                    string newFileName = $"{fileName}_Save{extension}";
                    string newFilePath = Path.Combine(Path.GetDirectoryName(filePath), newFileName);

                    // 调用方法读取文件数据
                    Dictionary<string, string[]> csvData = await CsvReaderHelper.ReadCsv(filePath, "二维码");

                    List<TraceRivete> traceRivetes = new List<TraceRivete>();

                    string station = string.Empty;
                    string traceId = string.Empty;
                    string dateTime = string.Empty;

                    // 循环存储
                    for (int i = 0; i <= csvData["二维码"].Length - 1; i++)
                    {
                        // 实例化存储类
                        TraceRivete traceRivete = new TraceRivete();

                        traceRivete.Result = csvData["结果"][i];

                        dateTime = traceRivete.DataTime = $"{csvData["日期"][i]} {csvData["时间"][i]}";

                        traceRivete.Pulling = csvData["拉力"][i];

                        traceRivete.PullingMax = csvData["拉力上限"][i];

                        traceRivete.PullingMin = csvData["拉力下限"][i];

                        traceRivete.Displacement = csvData["位移量"][i];

                        traceRivete.DisplacementMax = csvData["位移上限"][i];

                        traceRivete.DisplacementMin = csvData["位移下限"][i];

                        traceId = traceRivete.TraceId = csvData["二维码"][i].Equals("null") ? csvData["批次"][i] : csvData["二维码"][i];

                        traceRivete.PointNo = csvData["点位编号"][i];

                        traceRivete.PointCount = csvData["点位计数"][i];

                        traceRivete.ToolNo = csvData["枪号"][i];

                        station = traceRivete.Station = csvData["工位号"][i];

                        traceRivetes.Add(traceRivete);
                    }

                    Tools.ProduceLogText($"成功保存{csvData["二维码"].Length}条拉铆数据，关联码为[{traceId}],工位[{station}]");


                    try
                    {
                        // 重命名文件（如果已存在则跳过或覆盖）
                        if (!File.Exists(newFilePath))
                        {
                            File.Move(filePath, newFilePath);

                            // 调用存储
                            orderDao.SaveRiveteData(traceRivetes, traceId);

                            // 工单号绑定
                            OrderSingletonModel orderSingletonModel = OrderSingleton.GetOrderId(station);

                            if (orderSingletonModel != null)
                            {
                                string orderId = orderSingletonModel.OrderId;

                                if (string.IsNullOrEmpty(orderId))
                                    continue;

                                if (!orderDao.OrderTraceIsSave(traceId))
                                    orderDao.OrderTraceSave(traceId, orderId,orderSingletonModel.LineName);
                            }

                            string result = fileName.Split('_')[2];

                            // 过站数据绑定
                            if (!orderDao.ProcessDataFromCsvIsSave(traceId, station))
                                orderDao.SaveProcessDataFromCsv(traceId, station, dateTime, result);

                            //推送拉铆工艺数据
                            _ = Task.Run(() => { ViewService.InsertLineMesData(traceId, station, traceRivetes); });
                        }
                        else
                        {
                            Tools.ProduceLogTextError($"文件已存在，跳过: {newFileName}");

                            File.Delete(filePath);
                        }
                    }
                    catch (IOException ex)
                    {
                        Tools.ProduceLogTextError($"标签打入失败: {ex.Message}");
                    }
                }
            }
        }

        /// <summary>
        /// 读取压铆的CSV数据文件
        /// </summary>
        /// <returns></returns>
        public async Task ReadCSVData()
        {
            while (true)
            {
                List<string> ips = new List<string>()
                {
                    "192.168.10.21",
                    "192.168.10.20"
                };

                for (global::System.Int32 i = 0; i < ips.Count; i++)
                {
                    await ClinchRead(ips[i]);
                }

                await Task.Delay(1000);
            }
        }

        private async Task ClinchRead(string ip)
        {
            await Task.Delay(2000);

            string date = $"{DateTime.Now.ToString("yyyy")}{DateTime.Now.ToString("MM")}";

            // 初始化日期
            string date1 = $"{DateTime.Now.ToString("yyyy")}{DateTime.Now.ToString("MM")}{DateTime.Now.ToString("dd")}";

            // 初始化文件夹路径
            string directory = $@"\\{ip}\ym\before\Data_info\{date}\{date1}";

            string userName = ip.Contains("20") ? "ctos" : "administrator";

            try
            {
                if (Directory.Exists(directory))
                {
                    // 获取目录下所有CSV文件路径
                    string[] csvFiles = Directory.GetFiles(directory, "*.csv");

                    foreach (string filePath in csvFiles)
                    {
                        if (filePath.Contains("_Save"))
                            continue;

                        // 提取文件名和扩展名
                        string fileName = Path.GetFileNameWithoutExtension(filePath);
                        string extension = Path.GetExtension(filePath); // 如 ".csv"

                        // 构建新文件名：原文件名 + "_Save" + 扩展名
                        string newFileName = $"{fileName}_Save{extension}";
                        string newFilePath = Path.Combine(Path.GetDirectoryName(filePath), newFileName);

                        // 调用方法读取文件数据
                        Dictionary<string, string[]> csvData = await CsvReaderHelper.ReadCsv(filePath, "二维码");

                        // 实例化存储类
                        TraceClinch traceClinch = new TraceClinch();

                        List<TraceClinch> traceClinchs = new List<TraceClinch>();

                        // 循环存储
                        for (int i = 0; i <= csvData["二维码"].Length - 1; i++)
                        {
                            string dateString = $"{csvData["日期"][i]} {csvData["时间"][i]}";
                            string format = "yyyyMMdd HH:mm:ss";

                            // 使用固定区域性确保格式解析稳定
                            DateTime dateTime = DateTime.ParseExact(
                                dateString,
                                format,
                                CultureInfo.InvariantCulture
                            );

                            traceClinch.Result = csvData["结果"][i];

                            traceClinch.DataTime = dateTime.ToString();

                            traceClinch.Pressure = csvData["压力"][i];

                            traceClinch.PressureMax = csvData["压力上限"][i];

                            traceClinch.PressureMin = csvData["压力下限"][i];

                            traceClinch.Displacement = csvData["位移量"][i];

                            traceClinch.DisplacementMax = csvData["位移上限"][i];

                            traceClinch.DisplacementMin = csvData["位移下限"][i];

                            traceClinch.TraceId = csvData["二维码"][i];

                            traceClinch.PointNo = csvData["点位编号"][i];

                            traceClinch.PointCount = csvData["点位计数"][i];

                            traceClinch.ToolNo = csvData["枪号"][i];

                            traceClinch.Station = csvData["工位号"][i];

                            // 调用存储
                            if (!orderDao.ClinchDataIsSave(traceClinch.TraceId, traceClinch.PointCount, traceClinch.Station))
                                orderDao.SaveClinchData(traceClinch);

                            traceClinchs.Add(traceClinch);
                        }

                        Tools.ProduceLogText($"成功保存{csvData["二维码"].Length}条压铆数据，关联码为[{traceClinch.TraceId}],工位[{traceClinch.Station}]");

                        try
                        {
                            // 重命名文件（如果已存在则跳过或覆盖）
                            if (!File.Exists(newFilePath))
                            {
                                File.Move(filePath, newFilePath);

                                if (string.IsNullOrEmpty(traceClinch.TraceId))
                                {
                                    Tools.ProduceLogTextError($"[{traceClinch.Station}]，压铆存在空码！！");

                                    continue;
                                }
                                exitService.OrderProduction(traceClinch.Station);
                                // 工单号绑定
                                OrderSingletonModel orderSingletonModel = OrderSingleton.GetOrderId(traceClinch.Station);

                                if (orderSingletonModel != null)
                                {
                                    string orderId = orderSingletonModel.OrderId;

                                    if (string.IsNullOrEmpty(orderId))
                                        continue;

                                    if (!orderDao.OrderTraceIsSave(traceClinch.TraceId))
                                        orderDao.OrderTraceSave(traceClinch.TraceId, orderId, orderSingletonModel.LineName);
                                }

                                // 过站信息绑定,获取结果
                                string result = fileName.Split('_')[2];

                                if (!orderDao.ProcessDataFromCsvIsSave(traceClinch.TraceId, traceClinch.Station))
                                    orderDao.SaveProcessDataFromCsv(traceClinch, result);

                                //推送压铆工艺数据
                                _ = Task.Run(() => { ViewService.InsertLineMesData(traceClinch.TraceId, traceClinch.Station, traceClinchs); });
                            }
                            else
                            {
                                Tools.ProduceLogTextError($"文件已存在，跳过: {newFileName}");

                                File.Delete(filePath);
                            }
                        }
                        catch (IOException ex)
                        {
                            Tools.ProduceLogTextError($"标签打入失败: {ex.Message}");
                        }
                    }
                }

                /*using (new NetworkConnection(Path.GetDirectoryName($@"\\{ip}\ym\"), new NetworkCredential(userName, "asd")))
                {

                    
                }*/
            }
            catch (DirectoryNotFoundException)
            {
                Tools.ProduceLogTextError($"压铆数据文件目录不存在: {directory}");
            }
            catch (UnauthorizedAccessException)
            {
                Tools.ProduceLogTextError("压铆数据文件没有访问权限，请检查凭据。");
            }
            catch (Exception ex)
            {
                Tools.ProduceLogTextError($"[{ip}]压铆数据文件读取发生错误: {ex.Message}");
            }
        }

        /// <summary>
        /// 时间同步
        /// </summary>
        /// <returns></returns>
        public async Task TimeToPlc()
        {
            int timer = 1000;

            while (true)
            {
                foreach (var item in readPlcList)
                {
                    if (item == null || !item.plc.IsConnected)
                        continue;

                    DateTime now = DateTime.Now;

                    byte[] bytes = ToDateAndTimeBytes(now);

                    item.plc.WriteBytes(DataType.DataBlock, 5004, 0, bytes);

                    timer = 86400000;

                    Tools.ProduceLogText("时间同步触发成功");
                }

                await Task.Delay(timer);
            }
        }

        // 辅助函数：将0-99的整数转换为BCD码
        private static byte ToBcd(int value)
        {
            return (byte)((value / 10 << 4) | (value % 10));
        }

        // 转换DateTime为PLC的DATE_AND_TIME字节数组
        public static byte[] ToDateAndTimeBytes(DateTime dt)
        {
            byte[] bytes = new byte[8];

            // 年（后两位和前两位）
            bytes[0] = ToBcd(dt.Year % 100);   // 后两位
            bytes[1] = ToBcd(dt.Year / 100);   // 前两位

            // 月、日、时、分、秒
            bytes[2] = ToBcd(dt.Month);
            bytes[3] = ToBcd(dt.Day);
            bytes[4] = ToBcd(dt.Hour);
            bytes[5] = ToBcd(dt.Minute);
            bytes[6] = ToBcd(dt.Second);

            // 毫秒百位（0-9）和星期几
            int weekDay = dt.DayOfWeek == DayOfWeek.Sunday ? 7 : (int)dt.DayOfWeek;
            byte msBcd = ToBcd(dt.Millisecond / 100); // 取百位值
            bytes[7] = (byte)((msBcd << 4) | weekDay); // 高4位=毫秒百位，低4位=星期

            return bytes;
        }
    }
}
